package com.stars.easyms.logger.support.logback.handler;

import ch.qos.logback.core.OutputStreamAppender;
import ch.qos.logback.core.encoder.Encoder;
import com.stars.easyms.logger.support.logback.pattern.EasyMsPatternLayoutEncoder;
import lombok.extern.slf4j.Slf4j;

import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>className: EasyMsOutputStreamAppender</p>
 * <p>description: EasyMs自定义异步写的实现类</p>
 *
 * @author guoguifang
 * @date 2019-08-19 20:00
 * @since 1.3.0
 */
@Slf4j
public final class EasyMsOutputStreamAppender {

    private final OutputStream outputStream;

    private boolean immediateFlush;

    private final ReentrantLock logLock;

    EasyMsOutputStreamAppender(OutputStreamAppender outputStreamAppender) {
        this.outputStream = outputStreamAppender.getOutputStream();
        this.logLock = new ReentrantLock(true);
        this.checkImmediateFlush(outputStreamAppender);
    }

    public void write(List<byte[]> list) {
        byte[] writeBytes = byteMergerAll(list);
        logLock.lock();
        try {
            outputStream.write(writeBytes);
            if (immediateFlush) {
                outputStream.flush();
            }
        } catch (Exception e) {
            log.error("Write log fail!", e);
        } finally {
            logLock.unlock();
        }
    }

    private byte[] byteMergerAll(List<byte[]> list) {
        int lengthByte = list.stream().mapToInt(item -> item.length).sum();
        byte[] allByte = new byte[lengthByte];
        int countLength = 0;
        for (byte[] b : list) {
            System.arraycopy(b, 0, allByte, countLength, b.length);
            countLength += b.length;
        }
        return allByte;
    }

    private void checkImmediateFlush(OutputStreamAppender outputStreamAppender) {
        Encoder encoder = outputStreamAppender.getEncoder();
        this.immediateFlush = !(encoder instanceof EasyMsPatternLayoutEncoder) || ((EasyMsPatternLayoutEncoder) encoder).isImmediateFlush();
    }
}